-------------------------------------------------------------------------------
-- This is the file that contains all of the codes source of Lua for one peer
-------------------------------------------------------------------------------

--require("splay.base") 
local io = require("io")
--require("luarocks.require")
require("luasql.mysql")
local socket = require("socket")

local math = require("math")

package.cpath = "./lib/?.so"
local geoip = require("geoip")

print(job.me.ip.."\n")

-------------------------------------------------------------------------------
-- The parameters of this system
-------------------------------------------------------------------------------
-- The MYSQL's parameters
local mysqlParameters = {}
mysqlParameters["type"] = "mysql"
mysqlParameters["database"] = "distrinet"
mysqlParameters["user"] = "distrinet"
mysqlParameters["password"] = "distrinet"
mysqlParameters["hostIP"] = "localhost"
mysqlParameters["port"] = 3306

-------------------------------------------------------------------------------
-- Log file
-------------------------------------------------------------------------------
function logfile(str)
	local file = io.open("log.txt", "a")
	file:write("\n[")
	file:write(os.date("%X", os.time()))
	local _, mili = string.match(tostring(socket.gettime()) , "(.*)%p(.*)")
	file:write(":"..mili.."]: ")
	file:write(tostring(str))
	file:close()
end

-------------------------------------------------------------------------------
-- The global variables in the programme
-------------------------------------------------------------------------------
-- Connect Database
env = assert (luasql.mysql())
local connectDatabase = assert (env:connect(mysqlParameters["database"], mysqlParameters["user"], mysqlParameters["password"], mysqlParameters["hostIP"], mysqlParameters["port"]))
--local execution
--local row

-------------------------------------------------------------------------------
-- Get parameter function
-------------------------------------------------------------------------------
function getParameter(parameterName)
	execution = connectDatabase:execute(string.format([[SELECT * FROM configuration]]))
	row = execution:fetch({}, "a")
	return tostring(row[tostring(parameterName)])
end

-------------------------------------------------------------------------------
-- Split a string into lines separated by either DOS or Unix line endings, creating a table out of the results. 
-- http://lua-users.org/wiki/SplitJoin
-------------------------------------------------------------------------------
local function lines(str)
	local t = {}
	local function helper(line) table.insert(t, line) return "" end
	helper((str:gsub("(.-)\r?\n", helper)))
	return t
end

-------------------------------------------------------------------------------
-- update table voteResult
-------------------------------------------------------------------------------
local function updateVoteResult(urlStr)
	print("updateVoteResult(" .. urlStr .. ")")
	local exeSelectURLFromVoteResult = connectDatabase:execute(string.format([[SELECT * FROM voteResult WHERE url = '%s']], tostring(urlStr)))
	local rowSelectURLFromVoteResult = exeSelectURLFromVoteResult:fetch ({}, "a")
	if (rowSelectURLFromVoteResult) then
		-- Update table voteResult
		local exeUpdate = connectDatabase:execute(string.format([[UPDATE voteResult SET numberVote = '%d' WHERE url = '%s']], tonumber(rowSelectURLFromVoteResult.numberVote) + 1 , tostring(urlStr)))
	else
		-- Insert new line in the table voteResult
		local exeInsert = connectDatabase:execute(string.format([[INSERT INTO voteResult (url, numberVote) VALUES('%s', '%d')]], tostring(urlStr), tonumber(1)))
		local results, error = geoip.geocity("./lib/GeoLiteCity.dat", tostring(urlStr))
		--print("latitude  = "..results["latitude"])
		--print("longitude = "..results["longitude"])
		if (results) then
			local exeUpdate = connectDatabase:execute(string.format([[UPDATE voteResult SET longitude = '%s', latitude = '%s' WHERE url = '%s']],tostring(results["longitude"]), tostring(results["latitude"]), tostring(urlStr)))
		end
	end
end

-------------------------------------------------------------------------------
-- update table voteResultUrlUrl
-------------------------------------------------------------------------------
local function updatevoteResultUrlUrl(url1, url2, score)
	print("updatevoteResultUrlUrl(" .. url1 .. ", " .. url2 .. ", " .. score .. ")")
	local exe1 = connectDatabase:execute(string.format([[SELECT * FROM voteResultUrlUrl WHERE url1 = '%s' and url2 = '%s']], tostring(url1), tostring(url2)))
	local row1 = exe1:fetch ({}, "a")
	if row1 then -- existed
		local newScore = tonumber(score) + tonumber(row1.score)
		local exeUpdate1 = connectDatabase:execute(string.format([[UPDATE voteResultUrlUrl SET score = '%d' WHERE url1 = '%s' and url2 = '%s']], tonumber(newScore), tostring(url1), tostring(url2)))
		local exeUpdate2 = connectDatabase:execute(string.format([[UPDATE voteResultUrlUrl SET score = '%d' WHERE url1 = '%s' and url2 = '%s']], tonumber(newScore), tostring(url2), tostring(url1)))
	else -- insert new
		local exeInsert1 = connectDatabase:execute(string.format([[INSERT INTO voteResultUrlUrl (url1, url2, score) VALUES('%s', '%s', '%d')]], tostring(url1), tostring(url2), tonumber(score)))
		local exeInsert2 = connectDatabase:execute(string.format([[INSERT INTO voteResultUrlUrl (url1, url2, score) VALUES('%s', '%s', '%d')]], tostring(url2), tostring(url1), tonumber(score)))
	end
end

-------------------------------------------------------------------------------
-- update table voteResultQryUrl
-------------------------------------------------------------------------------
local function updatevoteResultQryUrl(query, url, score)
	print("updatevoteResultQryUrl(" .. query .. ", " .. url .. ", " .. score .. ")")
	local exe1 = connectDatabase:execute(string.format([[SELECT * FROM voteResultQryUrl WHERE query = '%s' and url = '%s']], tostring(query), tostring(url)))
	local row1 = exe1:fetch ({}, "a")
	if row1 then -- existed
		local newScore = tonumber(score) + tonumber(row1.score)
		local exeUpdate1 = connectDatabase:execute(string.format([[UPDATE voteResultQryUrl SET score = '%d' WHERE query = '%s' and url = '%s']], tonumber(newScore), tostring(query), tostring(url)))
	else -- insert new
		local exeInsert1 = connectDatabase:execute(string.format([[INSERT INTO voteResultQryUrl (query, url, score) VALUES('%s', '%s', '%d')]], tostring(query), tostring(url), tonumber(score)))
	end
end

-- Create a socket server
local server = socket.tcp()
server:bind(tostring(job.me.ip), getParameter("SPLAYD_PORT"))
server:listen()

local client
local receivedMsgCode

print("\n listen ....\n")
-------------------------------------------------------------------------------
-- Get Universally Unique Identifier
-------------------------------------------------------------------------------
function getUUID ()
	execution = connectDatabase:execute(string.format([[SELECT uuid()]]))
	local row = execution:fetch({}, "a")
	return row["uuid()"]
end

-------------------------------------------------------------------------------
-- Crypt a message by a key using algorithmes DES
-------------------------------------------------------------------------------
function crypt(key, message)
	local cryptID = getUUID()
	local input = "/tmp/input"..tostring(cryptID)..".txt"
	local output = "/tmp/output"..tostring(cryptID)..".txt"
	
	local file1 = assert(io.open(input, "w"))
    file1:write(message)
    file1:close()
    
    os.execute(string.format([[openssl enc -des -in '%s' -out '%s' -k '%s']], tostring(input), tostring(output), tostring(key)))

	local file2 = assert(io.open(output, "rb"))
    local cryptedMessage = file2:read("*all")
    file2:close()

	print("cryptedMessage = "..cryptedMessage)
	
	-- Delete the files input.txt and output.txt
	os.execute(string.format([[rm -fr '%s' '%s']], tostring(input), tostring(output)))
	
	return cryptedMessage
end

-------------------------------------------------------------------------------
-- Decrypt data by key given using the algorithme DES
-------------------------------------------------------------------------------
function decrypt (key, cryptedMessageFileName)
	local decryptID = getUUID()
--	local input = "/tmp/input"..tostring(decryptID)..".txt"
	local output = "/tmp/output"..tostring(decryptID)..".txt"
	
	print("key = ".. key)
	print("fileName = "..cryptedMessageFileName)
	os.execute(string.format([[openssl enc -d -des -in '%s' -out '%s' -k '%s']], tostring(cryptedMessageFileName), tostring(output), tostring(key)))	
	
	local file2 = assert(io.open(output, "rb"))
    local message = file2:read("*all")
    file2:close()
	
	print("message = "..message)
	
	-- Delete the files input.txt and output.txt
	os.execute(string.format([[rm -fr '%s']], tostring(output)))
	
	return message
		
end

-------------------------------------------------------------------------------
-- The main loop 
-------------------------------------------------------------------------------
--os.remove("log.txt")
logfile("INSTITUTIONAL PEER : "..tostring(job.me.ip).." Start log..........")
while true do
	client = server:accept()
	receivedMsgCode = client:receive("*line")
	print("\n Message Code : "..receivedMsgCode.."\n")
	logfile("MESSAGE CODE : "..receivedMsgCode)
	logfile("from: "..tostring(client:getpeername()))
	
	--*************************************************************************
	-- List the available Peer's IP in the network, Message Code = IPS
	--*************************************************************************
	if (receivedMsgCode == "GET_IPS") then
		local IPsString = ""
		for pos, sl in pairs(job.nodes) do
			print("\n pos : "..pos.." ip : "..sl.ip)
			logfile("(s) ip: "..sl.ip)
			IPsString = tostring(IPsString)..tostring(sl.ip).."&"
		end
		client:send(IPsString.."\n")
	end
	-- End of List the available Peer

	--*************************************************************************
	-- Change password in the database and send the confirmation email to user, Message Code = CHANGE_PASSWORD
	--*************************************************************************
	if (receivedMsgCode == "CHANGE_PASSWORD") then
		local IPMP = client:receive("*line")
		local userID = client:receive("*line")
		local email = client:receive("*line")
		local password = client:receive("*line")
		local newpassword = client:receive("*line")
		logfile("(r) IPMP: "..IPMP)
		logfile("(r) userID: "..userID)
		logfile("(r) email: "..email)
		logfile("(r) password: "..password)
		logfile("(r) newpassword: "..newpassword)
		
		local execution = connectDatabase:execute(string.format([[SELECT * FROM master_peer WHERE userID = '%d' and password = '%s']], tonumber(userID), tostring(password)))
        local row = execution:fetch({}, "a")
        
        if (row) then
        	-- answer the client
        	client:send("OK_CHANGE_PASSWORD\n")
        	logfile("(s) msg: OK_CHANGE_PASSWORD")
        else
        	client:send("CHANGE_PASSWORD_FAILED\n")
        	logfile("(s) msg: CHANGE_PASSWORD_FAILED")
        end
	end
	-- End of CHANGE_PASSWORD
	
	--*************************************************************************
	-- UNREGISTRATION, Message Code = UNREGISTRATION
	--*************************************************************************
	if (receivedMsgCode == "UNREGISTRATION") then
		local userID = client:receive("*line")
		local password = client:receive("*line")
		logfile("(r) userID: "..userID)
		logfile("(r) password: "..password)
		
		local execution = connectDatabase:execute(string.format([[SELECT * FROM master_peer WHERE userID = '%d' and password = '%s']], tonumber(userID), tostring(password)))
		local row = execution:fetch({}, "a")
		
		if (row) then
			client:send(tostring(row.email).."\n")
			print("send = "..tostring(row.email))
			logfile("(s) email: "..row.email)
		else 
			client:send("NOT_FOUND\n")
			logfile("(s) msg: NOT_FOUND")
		end
	end
	-- End of UNREGISTRATION
	
	--*************************************************************************
	-- Logout, Message Code = LOGOUT
	--*************************************************************************
	if (receivedMsgCode == "LOGOUT") then
		local userID = client:receive("*line")
		logfile("(r) userID: "..userID )
		
		local execution = connectDatabase:execute(string.format([[SELECT * FROM master_peer WHERE userID = '%d']], tonumber(userID)))
		
        local row = execution:fetch({}, "a")
        execution:close()  
        if (row) then

			execution = connectDatabase:execute(string.format([[UPDATE master_peer SET status = "INACTIVE" WHERE userID = '%d']],tonumber(userID)))
      		client:send("OK_CHECKLOGOUT\n")
			print("\nOK_CHECKLOGOUT\n")
			logfile("(s) msg: OK_CHECKLOGOUT")
        	-- Gui thu bao cho chinh chu biet de co the thay doi password
        else
	        client:send("Logout fail...\n")
	        print("\nLogout fail...\n")
	        logfile("(s) msg: Logout fail...")
	    end   
	end
	-- End of Logout
	
	--*************************************************************************
	-- Expired Session, Message Code = EXPIREDSESSION
	--*************************************************************************
	if (receivedMsgCode == "EXPIREDSESSION") then
		local userID = client:receive("*line")
		logfile("(r) userID: "..userID)
		
		execution = connectDatabase:execute(string.format([[UPDATE master_peer SET status = "INACTIVE" WHERE userID = '%d']],tonumber(userID)))
	end
	-- End of Expired Session
	
	--*************************************************************************
	-- Check Access, Message Code = CHECK_ACCESS
	--*************************************************************************
	if (receivedMsgCode == "CHECK_ACCESS") then

		print("\n Client send :")
        local userID = client:receive("*line")
        print("\n userID : "..userID)
        local password = client:receive("*line")
        print("\n password : "..password)
        logfile("(r) userID: "..userID)
        logfile("(r) password: "..password)
        
		local execution = connectDatabase:execute(string.format([[SELECT * FROM master_peer WHERE userID = '%d' and password = '%s']], tonumber(userID), tostring(password)))
        local row = execution:fetch({}, "a")
		
		local sessionTimeOut = getParameter("WEB_SESSION_TIME_OUT")
        if (row) then
        	client:send("AUTHORISED\n") 
			logfile("(s) msg: AUTHORISED")
			
        	if ((row.status == "INACTIVE") or (tonumber(row.timeStart) + tonumber(sessionTimeOut) < tonumber(os.time()))) then
				print("OK_CHECK_ACCESS")
	        	client:send("OK_CHECK_ACCESS\n")
	        	client:send(row.email.."\n")
	        	logfile("(s) msg: OK_CHECK_ACCESS")
	        	logfile("(s) email: "..row.email)
	        	
				-- Update database
				local IPAP = client:receive("*line")
				print("IPAP = "..IPAP)
				logfile("(r) IPAP: "..IPAP)
				local sessionID = client:receive("*line")
				print("sessionID = "..sessionID)
				logfile("(r) sessionID: "..sessionID)
				
				execution = connectDatabase:execute(string.format([[UPDATE master_peer SET status = "ACTIVE", IPAP = '%s', sessionID = '%d', timeStart = '%s' WHERE userID = '%d' and password = '%s']],tostring(IPAP), tonumber(sessionID), tostring(os.time()), tonumber(userID), tostring(password)))
      
        	else
        		client:send("This user is already activated !!!\n")
        		print("This user is already activated !!!")
        		logfile("(s) msg: This user is already activated !!!")
	       		-- Gui thu bao cho chinh chu biet de co the thay doi password
			end  		
		else
        	client:send("NOT_AUTHORISED\n")
        	logfile("(s) msg: NOT_AUTHORISED")
        end

    end
	-- End of CHECKACCESS

	--*************************************************************************
	-- Create token, Message Code = CREATETOKEN
	--*************************************************************************
	if(receivedMsgCode == "CREATE_TOKEN") then
		local userID = client:receive("*line")
		print("\nuserID = "..userID)
		logfile("(r) userID: "..userID)
		
		local exeLastTokenTime = connectDatabase:execute(string.format([[SELECT MAX(timeCreate) FROM token WHERE userID = '%d']], tonumber(userID)))
		local rowLastTokenTime = exeLastTokenTime:fetch({}, "a")
		
		local numOfToken = getParameter("TOKEN_GET_NUMBER")
				
		if (rowLastTokenTime["MAX(timeCreate)"] == nil) then
			for i = 1, numOfToken do
				local tokenID = getUUID()
				--[[ c1, c2 can be derived from token
				local c1 = getUUID()
				local c2 = getUUID()
				--]]
				local l = string.len(tokenID)
				local l2 = math.floor((l / 2) + 0.5)
				local c1 = "#$" .. string.sub(tokenID, 1, l2) .. "$#"
				local c2 = "#$" .. string.sub(tokenID, l2 + 1, l) .. "$#"
				 
				local exeInsertNewToken = connectDatabase:execute(string.format([[INSERT INTO token (tokenID, userID, c1, c2, status, timeCreate) VALUES('%s', '%d', '%s', '%s', '%s', '%s')]], tostring(tokenID), tonumber(userID), tostring(c1), tostring(c2), "INACTIVE", tostring(os.time())))	
			end
			client:send("CREATED_NEW_TOKENS\n")
			print("\nCREATED_NEW_TOKENS\n")
			logfile("(s) msg: CREATED_NEW_TOKENS")
		else
			local remainTime = tonumber(rowLastTokenTime["MAX(timeCreate)"]) + tonumber(getParameter("TOKEN_GET_PERIOD")) - tonumber(os.time())  
			if (remainTime <= 0) then
				for i = 1, numOfToken do
					local tokenID = getUUID()
					--[[ c1, c2 can be derived from token
					local c1 = getUUID()
					local c2 = getUUID()
					--]]

					local l = string.len(tokenID)
					local l2 = math.floor((l / 2) + 0.5)
					local c1 = "#$" .. string.sub(tokenID, 1, l2) .. "$#"
					local c2 = "#$" .. string.sub(tokenID, l2 + 1, l) .. "$#"

					local exeInsertNewToken = assert (connectDatabase:execute(string.format([[INSERT INTO token (tokenID, userID, c1, c2, status, timeCreate) VALUES('%s', '%d', '%s', '%s', '%s', '%s')]], tostring(tokenID), tonumber(userID), tostring(c1), tostring(c2), "INACTIVE", tostring(os.time()))))	
				end
				client:send("CREATED_NEW_TOKENS\n")
				print("\nCREATED_NEW_TOKENS\n")
				logfile("(s) msg: CREATED_NEW_TOKENS")
			else
				client:send("WAITING\n")
				client:send(tostring(math.ceil(remainTime/60)).."\n")
				print("\nWAITING : "..tostring(math.ceil(remainTime/60)).." minutes...")
				logfile("(s) msg: WAITING")
				logfile("(s) remainTime: "..tostring(remainTime))	
			end
		end
		
	end
	-- End of CREATETOKEN

	--*************************************************************************
	-- Tokens, Message Code = TOKENS
	--*************************************************************************
	if (receivedMsgCode == "TOKENS") then
		local userID = client:receive("*line")
		logfile("(s) userID: "..userID)
		
		local exeTokens = connectDatabase:execute(string.format([[SELECT * FROM token WHERE userID = '%d' and status = "INACTIVE"]], tonumber(userID)))
		rowTokens = exeTokens:fetch ({}, "a")
		while (rowTokens) do
			client:send(tostring(rowTokens.tokenID).."&"..tostring(rowTokens.timeCreate).."\n")
			logfile("(s) tokenID: "..tostring(rowTokens.tokenID).."&"..tostring(rowTokens.timeCreate))
			rowTokens = exeTokens:fetch ({}, "a")
		end	
		client:send("FINISH&FINISH\n")
		logfile("(s) msg: FINISH&FINISH")
	end
	-- End of Tokens

	--*************************************************************************
	-- Request two codes of token, Message Code = REQUEST_2CODES_OF_TOKEN
	--*************************************************************************
	if (receivedMsgCode == "REQUEST_2CODES_OF_TOKEN") then
		local tokenID = client:receive("*line")
		logfile("(r) tokenID: "..tokenID)
		
		execution = connectDatabase:execute(string.format([[SELECT * FROM token WHERE tokenID = '%s']],tostring(tokenID)))
		row = execution:fetch ({}, "a")
		if (row) then
			client:send(tostring(row.c1).."\n")
			client:send(tostring(row.c2).."\n")
			logfile("(s) c1: "..row.c1)
			logfile("(s) c2: "..row.c2)
		else 
			client:send("123456789\n") 
			client:send("123456789\n")
		
		end
	end 
	-- End of REQUEST_2CODES_OF_TOKEN

	--*************************************************************************
	-- Tranfer of vote, done by intermediate peer, Message Code = TRANSFER_VOTE
	--*************************************************************************
	if (receivedMsgCode == "TRANSFER_VOTE") then
		local voteSessionID = client:receive("*line")
		local code = client:receive("*line")
		local messageCrypt = client:receive("*all")
		logfile("(r) voteSessionID: "..voteSessionID)
		logfile("(r) code: "..code)
		logfile("(r) messageCrypt: "..messageCrypt)
		
		-- transfer to vote peer
		local connectToVotePeer = socket.tcp()
		connectToVotePeer:connect(tostring(getParameter("VOTE_PEER_IP")), getParameter("SPLAYD_PORT"))
		connectToVotePeer:send("SEND_VOTE\n")
		connectToVotePeer:send(tostring(voteSessionID).."\n") -- send ID
		connectToVotePeer:send(tostring(code).."\n") -- send code
		connectToVotePeer:send(messageCrypt) -- send messageCrypt
		connectToVotePeer:close()
		
		local votePeer = tostring(getParameter("VOTE_PEER_IP"))
		logfile("(s:"..votePeer..") MESSAGE CODE: SEND_VOTE")
		logfile("(s:"..votePeer..") voteSessionID: "..tostring(voteSessionID))
		logfile("(s:"..votePeer..") code: "..tostring(code))
		logfile("(s:"..votePeer..") messageCrypt: "..messageCrypt)
	end
	-- End of TRANSFER_VOTE
	
	--*************************************************************************
	-- send to Vote peer, Message Code = SEND_VOTE
	--*************************************************************************
	if (receivedMsgCode == "SEND_VOTE") then
		local voteSessionID = client:receive("*line")
		local code = client:receive("*line") 
		local messageCrypt = client:receive("*all")
		
		logfile("(r) voteSessionID: "..tostring(voteSessionID))
		logfile("(r) code: "..tostring(code))
		logfile("(r) messageCrypt: "..messageCrypt)

		print("messageCrypt = "..tostring(messageCrypt))
		
		-- Find in database
		local execution = connectDatabase:execute(string.format([[SELECT * FROM voteQueue WHERE voteSessionID = '%s']],tostring(voteSessionID)))
		local row = execution:fetch ({}, "a")
		if (row) then
			local c1 = tostring(row.code)
			local c2 = tostring(code)
			
			local input = "/tmp/input_2_"..tostring(voteSessionID)..".txt"
			print("input file = "..input)
			local file1 = assert(io.open(input, "wb"))
 			file1:write(messageCrypt)
    		file1:close()
			
			-- decrypter croise' deux message
			local message1 = decrypt(tostring(c1), tostring(input))
			local message2 = decrypt(tostring(c2), tostring(row.messageCrypt))
			
			-- Delete crypt file
			os.execute(string.format([[rm -fr '%s' '%s']], tostring(input), tostring(row.messageCrypt)))
			
			-- Distinguish between P3 and the vote side
			local p3 
			local url
			local findwww, _ = string.find(message1, "www.")
			if (findwww ~= nil) then
				p3 = message2
				url = message1
			else
				p3 = message1
				url = message2
			end
			
			-- Register the vote in table "vote" with status = "INACTIVE"
			local exeInsertIntoInVote = connectDatabase:execute(string.format([[INSERT INTO vote (voteSessionID, url, status) VALUES('%s', '%s', '%s')]], tostring(voteSessionID), tostring(url), "INACTIVE"))
			-- send message for verification of vote token
			local connectToP3 = socket.tcp()
			print("\np3 = "..p3)
			print("\nurl = "..url)
			print("\nc1 = "..c1)
			print("\nc2 = "..c2)
			
			logfile("(p) p3: "..p3)
			logfile("(p) url: "..url)
			logfile("(p) c1: "..c1)
			logfile("(p) c2: "..c2)
			
			connectToP3:connect(tostring(p3), getParameter("SPLAYD_PORT"))
			connectToP3:send("TRANSFER_TO_INTERMEDIATE\n")
			connectToP3:send(tostring(voteSessionID).."\n") -- voteSessionID
			connectToP3:send(tostring(c1).."\n") -- c1
			connectToP3:send(tostring(c2).."\n") -- c2
			connectToP3:close()
			
			logfile("(s:"..p3..") MESSAGE CODE: TRANSFER_TO_INTERMEDIATE")
			logfile("(s:"..p3..") voteSessionID: "..tostring(voteSessionID))
			logfile("(s:"..p3..") c1: "..tostring(c1))
			logfile("(s:"..p3..") c2: "..tostring(c2))
		else
			-- Register in the database 
			local input = "/tmp/input_1_"..tostring(voteSessionID)..".txt"
		
			local file1 = assert(io.open(input, "wb"))
			print("input file = "..input)
 			file1:write(messageCrypt)
    		file1:close()
			
			local exeInsertIntoQueue = connectDatabase:execute(string.format([[INSERT INTO voteQueue (voteSessionID, code, messageCrypt) VALUES('%s', '%s', '%s')]], tostring(voteSessionID), tostring(code), tostring(input)))
		    
		end
	end
	-- End of SEND_VOTE
	
	--*************************************************************************
	-- Action of intermediate peer P3, Message Code = TRANSFER_TO_INTERMEDIATE
	--*************************************************************************
	if (receivedMsgCode == "TRANSFER_TO_INTERMEDIATE") then
		local voteSessionID = client:receive("*line")
		local code = client:receive("*line")
		
		logfile("(r) voteSessionID: "..tostring(voteSessionID))
		logfile("(r) code: "..code)
		
		local c1 = ""
		local c2 = ""
		local IPMP = ""
		-- Find in database
		execution = connectDatabase:execute(string.format([[SELECT * FROM verificationQueue WHERE voteSessionID = '%s']],tostring(voteSessionID)))
		row = execution:fetch ({}, "a")
		if (row) then
			if (tostring(row.IPMP) ~= "") then
				IPMP = tostring(row.IPMP)
				c1 = tostring(code)
				c2 = client:receive("*line")
			else
				c1 = tostring(row.c1)
				c2 = tostring(row.c2)
				IPMP = client:receive("*line")
			end
		
			print("c1 = "..c1)
			print("c2 = "..c2)
			print("IPMP = ".. IPMP)
			
			logfile("(r+p) c1: "..tostring(c1))
			logfile("(r+p) c2: "..tostring(c2))
			logfile("(r+p) IPMP: "..tostring(IPMP))
			
			-- Connect to Master Peer for verification
			local connectToMasterPeer = socket.tcp()
			connectToMasterPeer:connect(tostring(IPMP), getParameter("SPLAYD_PORT"))
			connectToMasterPeer:send("REQUEST_VERIFICATION_TO_MP\n")
			connectToMasterPeer:send(tostring(voteSessionID).."\n") -- voteSessionID
			connectToMasterPeer:send(tostring(c1).."\n") -- c1
			connectToMasterPeer:send(tostring(c2).."\n") -- c2
			local answerFromMP = connectToMasterPeer:receive("*line")
			connectToMasterPeer:close()
			
			logfile("(s:"..tostring(IPMP)..") MESSAGE CODE: REQUEST_VERIFICATION_TO_MP")
			logfile("(s:"..tostring(IPMP)..") voteSessionID: "..voteSessionID)
			logfile("(s:"..tostring(IPMP)..") c1: "..tostring(c1))
			logfile("(s:"..tostring(IPMP)..") c2: "..tostring(c2))
			logfile("(r:"..tostring(IPMP)..") answerFromMP: "..answerFromMP)
			
			-- Connect to Vote Peer to inform the answer of Master Peer
			local connectToVotePeer = socket.tcp()
			connectToVotePeer:connect(tostring(getParameter("VOTE_PEER_IP")), getParameter("SPLAYD_PORT"))
			connectToVotePeer:send("ANSWER_TRANSFER_TO_INTERMEDIATE\n")			
			connectToVotePeer:send(tostring(voteSessionID).."\n") -- voteSessionID
			connectToVotePeer:send(tostring(answerFromMP).."\n") -- OK_VOTE_SESSION_ID/NOT_OK_VOTE_SESSION_ID
			connectToVotePeer:close()
			print("\n It's OK, You have successfully voted !!!")
			
			local votePeer = tostring(getParameter("VOTE_PEER_IP"))
			logfile("(s:"..votePeer..") MESSAGE CODE: ANSWER_TRANSFER_TO_INTERMEDIATE")
			logfile("(s:"..votePeer..") voteSessionID: "..tostring(voteSessionID))
			logfile("(s:"..votePeer..") answerFromMP: "..answerFromMP)
			
		else
			c1 = code
			local str = client:receive("*line")
			-- distinguish between IPMP and c2
			local _, numOfPoint = string.gsub(str, "%p","%p")
			if (numOfPoint == 3) then
				IPMP = tostring(str)
				c2 = ""
			else 
				c2 = tostring(str)
				IPMP = ""
			end

			logfile("(r+p) c1: "..tostring(c1))
			logfile("(r+p) c2: "..tostring(c2))
			logfile("(r+p) IPMP: "..tostring(IPMP))

			-- Register in the database 
			local exeInsertIntoQueue = connectDatabase:execute(string.format([[INSERT INTO verificationQueue (voteSessionID, c1, c2, IPMP) VALUES('%s', '%s', '%s', '%s')]], tostring(voteSessionID), tostring(c1), tostring(c2), tostring(IPMP)))
		end
	end
	-- End of SEND_VOTE
	
	--*************************************************************************
	-- Action of intermediate peer P3, Message Code = ANSWER_TRANSFER_TO_INTERMEDIATE
	--*************************************************************************
	if (receivedMsgCode == "ANSWER_TRANSFER_TO_INTERMEDIATE") then
		local voteSessionID = client:receive("*line")
		local answerFromMP = client:receive("*line")
		print("answerFromMP = "..answerFromMP)
		
		logfile("(r) voteSessionID: "..tostring(voteSessionID))
		logfile("(r) answerFromMP: "..tostring(answerFromMP))
		
		if (answerFromMP == "OK_VOTE_SESSION_ID") then
			local exeSelectFromVote = connectDatabase:execute(string.format([[SELECT * FROM vote WHERE voteSessionID = '%s']], tostring(voteSessionID)))
			local rowSelectFromVote = exeSelectFromVote:fetch ({}, "a")
			if (rowSelectFromVote) then
				-- Duc: Added to support raw-url, url-url, qry-url voting
				local voteStr = rowSelectFromVote.url
				print("--------------------- Vote string ----------------------")
				print(voteStr)
				print("--------------------------------------------------------")
				local score = 0
				local voteLines = lines(voteStr)
				if voteLines[4] then
					score = tonumber(voteLines[4])
				end
				--[[
				voteLines[1]: code
				voteLines[2]: raw-url -> url, url-url -> url1,  qry-url -> query
				voteLines[3]:                 url-url -> url2,  qry-url -> url
				voteLines[4]:                 url-url -> score, qry-url -> score
				]]--
				if voteLines[1] == "raw-url:" then -- BA's case
					updateVoteResult(voteLines[2])
				elseif voteLines[1] == "url-url:" then
					updateVoteResult(voteLines[2])
					updateVoteResult(voteLines[3])
					updatevoteResultUrlUrl(voteLines[2], voteLines[3], score)
				elseif voteLines[1] == "qry-url:" then
					local query = string.gsub(voteLines[2], "'", "''")
					updateVoteResult(voteLines[3])
					updatevoteResultQryUrl(query, voteLines[3], score)
				end
				-- Duc: End added to support raw-url, url-url, qry-url voting
				--local exeSelectURLFromVoteResult = connectDatabase:execute(string.format([[SELECT * FROM voteResult WHERE url = '%s']], tostring(rowSelectFromVote.url)))
				--local rowSelectURLFromVoteResult = exeSelectURLFromVoteResult:fetch ({}, "a")
				--if (rowSelectURLFromVoteResult) then
				--	-- Update table voteResult
				--	local exeUpdate = connectDatabase:execute(string.format([[UPDATE voteResult SET numberVote = '%d' WHERE url = '%s']], tonumber(rowSelectURLFromVoteResult.numberVote) + 1 , tostring(rowSelectFromVote.url)))
				--else
				--	-- Insert new line in the table voteResult
				--	local exeInsert = connectDatabase:execute(string.format([[INSERT INTO voteResult (url, numberVote) VALUES('%s', '%d')]], tostring(rowSelectFromVote.url), tonumber(1)))
				--	local results, error = geoip.geocity("./lib/GeoLiteCity.dat", tostring(rowSelectFromVote.url))
				--	--print("latitude  = "..results["latitude"])
				--	--print("longitude = "..results["longitude"])
				--	if (results) then
				--		local exeUpdate = connectDatabase:execute(string.format([[UPDATE voteResult SET longitude = '%s', latitude = '%s' WHERE url = '%s']],tostring(results["longitude"]), tostring(results["latitude"]), tostring(rowSelectFromVote.url)))
				--	end
				--end
			end
		end
		execution = connectDatabase:execute(string.format([[DELETE FROM vote WHERE voteSessionID = '%s']], tostring(voteSessionID)))
	end
	-- End of ANSWER_TRANSFER_TO_INTERMEDIATE
	
	--*************************************************************************
	-- Verify the token (two codes) in the database, Message Code = REQUEST_VERIFICATION_TO_MP
	--*************************************************************************
	if (receivedMsgCode == "REQUEST_VERIFICATION_TO_MP") then
		local voteSessionID = client:receive("*line")
		local c1 = client:receive("*line")
		local c2 = client:receive("*line")
		print("c1 = "..c1)
		print("c2 = "..c2)
	
		logfile("(r) c1: "..tostring(c1))
		logfile("(r) c2: "..tostring(c2))
	
		execution = connectDatabase:execute(string.format([[SELECT * FROM token WHERE ((c1 = '%s' and c2 = '%s') or(c1 = '%s') and (c2 = '%s')) and status = '%s']],tostring(c1), tostring(c2), tostring(c2), tostring(c1), "INACTIVE"))
		row = execution:fetch ({}, "a")
		if (row) then
			local tokenID = tostring(row.tokenID)
			-- Update database
			execution = connectDatabase:execute(string.format([[UPDATE token SET status = '%s' WHERE tokenID = '%s']], "ACTIVE", tostring(tokenID)))
			-- Answer OK
			client:send("OK_VOTE_SESSION_ID\n")
			logfile("(s) msg: OK_VOTE_SESSION_ID")
		else
			-- Answer NOT_OK
			client:send("NOT_OK_VOTE_SESSION_ID\n")
			logfile("(s) msg: NOT_OK_VOTE_SESSION_ID")
		end
	end
	-- End of REQUEST_VERIFICATION_TO_MP
	
	
	client:close()
end 
-- End of while

connectDatabase:close()
-- Close database